import { appPotentialClientAdd } from '@/api/member';
import type { AppPotentialClientAddData } from '@/api/member/types';
import { CacheEnum } from '@/enums/cacheEnum';
import {
  isObject,
  isReqUrl,
  isString
} from '@/utils/is';
import { ToastTitleEnum } from '@/enums/publicModuleEnum';
import { toSelectiveType } from './dynamicConfig';
import { unref } from 'vue';
import { navigateTo } from '@/router';
import { getWebAuthUrl } from '@/api/login';
import { useUserStoreWithOut } from '@/store/modules/user';
import { IsOfficialAccountEnum } from '@/enums/loginEnum';

/**
 * 给对象添加一些自定义方法
 * @param obj Object 实例
 * @returns Object
 */
export function setObjMethod<T = object>(obj: object = {}) {
  return Object.assign(
    Object.create({
      get(key: keyof T, value: any) {
        const v = (this as any)[key];
        return v === undefined ? value : v;
      },
    }),
    obj,
  ) as T;
}

export function getDynamicProps<T, U>(props: T): Partial<U> {
  const ret: Recordable = {};

  Object.keys(props as Object).map((key) => {
    ret[key] = unref((props as Recordable)[key]);
  });

  return ret as Partial<U>;
}

/**
 * 深度 合并
 * @param src
 * @param target
 * @returns
 */
export function deepMerge<T = any>(src: any = {}, target: any = {}): T {
  let key: string;
  for (key in target) {
    src[key] = isObject(src[key]) ? deepMerge(src[key], target[key]) : (src[key] = target[key]);
  }
  return src;
}

/**
 * 提示
 * @param data 提示内容
 * @param {string} icon 提示图标
 */
export function Toast(
  data?: UniApp.ShowToastOptions | string,
  icon?: 'success' | 'error' | 'none',
  duration = 2000,
  mask = true,
) {
  if (!data) return;
  data = isString(data) ? { title: data } : data;
  const success = data.success
  if (success) {
    setTimeout(success, data?.duration || duration)
  }
  delete data.success
  return uni.showToast({
    duration,
    icon: icon || 'none',
    mask: mask,
    ...data,
  });
}

/**
 * 微信分享文件到好友
 * @export
 * @param {string} url 文件网络地址
 * @param {string} [fileName] 自定义文件名，若留空则使用filePath中的文件名
 * @return {*}
 */
export function wxShareFile(url: string, fileName?: string): Promise<any> {
  console.log('url--->', url);
  /** 判断是否 本地路径 */
  let isLocalPath = false;
  if (url.includes(wx.env.USER_DATA_PATH)) isLocalPath = true;
  if (!isLocalPath && !isReqUrl(url)) return Promise.reject(new Error('URL格式错误'));
  return new Promise((reslove, reject) => {
    function share(path: string) {
      wx.shareFileMessage({
        filePath: path,
        fileName,
        success: () => reslove(true),
        fail: (err) => reject(err),
      });
    }
    if (!isLocalPath) {
      uni.showLoading({ title: '下载中...', mask: true });
      wx.downloadFile({
        url,
        header: {
          token: uni.getStorageSync(CacheEnum.token),
          appId: uni.getStorageSync(CacheEnum.appid),
          tenantId: uni.getStorageSync(CacheEnum.tenantId),
        },
        success: (r) => {
          share(r.tempFilePath);
          console.log(r.tempFilePath, '下载地址');
          uni.hideLoading();
        },
        fail: (err) => {
          Toast({
            title: ToastTitleEnum.DOWNFILETEXT,
            success: () => {
              uni.hideLoading()
              reject(err);
            }
          });
        },
      });
    } else {
      console.log(url, '下载地址');
      share(url);
    }
  });
}

/**
 * base64图片转本地图片
 * @export
 * @param {string} base64
 * @return {*}
 */
export function base64ToPath(base64: string): Promise<string> {
  base64 = 'data:image/png;base64,' + base64;
  const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
  return new Promise((resolve, reject) => {
    const fs = uni.getFileSystemManager();
    if (!format) {
      console.error('ERROR_BASE64SRC_PARSE');
      reject(new Error('ERROR_BASE64SRC_PARSE'));
    }
    const time = new Date().getTime();
    let env = wx.env;
    const filePath = `${env.USER_DATA_PATH}/${time}.${format}`;
    //let buffer = base64ToArrayBuffer(bodyData)
    fs.writeFile({
      filePath,
      data: base64.replace(/^data:\S+\/\S+;base64,/, ''),
      encoding: 'base64',
      // data: buffer,
      // encoding: 'binary',
      success() {
        resolve(filePath);
      },
      fail(err) {
        console.error('获取base64图片失败', JSON.stringify(err));
        reject(err);
      },
    });
  });
}

/**
 * @description 添加意向会员
 * @date 25/11/2022
 * @export
 * @param {AppPotentialClientAddData} data
 */
export function addProspectiveMembers(data: AppPotentialClientAddData) {
  appPotentialClientAdd(data);
  return uni.showModal({
    title: '提示',
    content: '申请成为正式会员, 即可解锁',
    confirmText: '申请解锁',
    confirmColor: '#2878FF',
    success: ({ confirm }) =>
      confirm &&
      toSelectiveType({
        linkUrl: 'selectiveType',
        isRedirectTo: true,
      }),
  });
}

/**
 * @description 授权微信公众号
 * @date 05/09/2023
 * @export
 */
export function authOfficialAccount() {
  return new Promise(async (resolve, reject) => {
    const { userInfo, setUserInfo } = useUserStoreWithOut()
    if (userInfo.isOfficialAccount !== IsOfficialAccountEnum.UNKNOWN) return resolve(true)
    const url = await getWebAuthUrl();
    if (!url) return reject()
    uni.showLoading({ title: '微信公众号授权中...', mask: true });
    navigateTo({
      name: 'webview',
      options: {
        url: url,
        title: '微信公众号授权中...',
        unLoadCallback: async () => {
          await setUserInfo()
          uni.hideLoading();
          resolve(true);
        },
      },
    });
  });
}

/**
 * @description svg转dataUrl
 * @date 06/05/2023
 * @export
 * @param {string} svg
 * @returns {string}
 */
export function svgToDataUrl(svg: string): string {
  if (!svg) return '';
  // 将被设置到 dataset 中的属性还原出来
  svg = svg.replace(/data-(.*?=(['"]).*?\2)/g, '$1');

  // 将被设置到 data-xlink-href 的属性还原出来
  svg = svg.replace(/xlink-href=/g, 'xlink:href=');

  // 将 dataset 中被变成 kebab-case 写法的 viewBox 还原出来
  svg = svg.replace(/view-box=/g, 'viewBox=');

  // 清除 SVG 中不应该显示的 title、desc、defs 元素
  svg = svg.replace(/<(title|desc|defs)>[\s\S]*?<\/\1>/g, '');

  // 为非标准 XML 的 SVG 添加 xmlns，防止视图层解析出错
  if (!/xmlns=/.test(svg)) svg = svg.replace(/<svg/, "<svg xmlns='http://www.w3.org/2000/svg'");

  // 对 SVG 中出现的浮点数统一取最多两位小数，缓解数据量过大问题
  svg = svg.replace(/\d+\.\d+/g, (match) => parseFloat(parseFloat(match).toFixed(2)).toString());

  // 清除注释，缓解数据量过大的问题
  svg = svg.replace(/<!--[\s\S]*?-->/g, '');

  // 模拟 HTML 的 white-space 行为，将多个空格或换行符换成一个空格，减少数据量
  svg = svg.replace(/\s+/g, ' ');

  // 对特殊符号进行转义，这里参考了 https://github.com/bhovhannes/svg-url-loader/blob/master/src/loader.js
  svg = svg.replace(/[{}\|\\\^~\[\]`"<>#%]/g, function (match) {
    return '%' + match[0].charCodeAt(0).toString(16).toUpperCase();
  });

  // 单引号替换为 \'，由于 kbone 的 bug，节点属性中的双引号在生成 outerHTML 时不会被转义导致出错
  // 因此 background-image: url( 后面只能跟单引号，所以生成的 URI 内部也就只能用斜杠转义单引号了
  svg = svg.replace(/'/g, "\\'");

  // 最后添加 mime 头部，变成 Webview 可以识别的 Data URI
  return 'data:image/svg+xml,' + svg.trim();
}

/**
 * @description 计算文字宽度
 * @date 21/05/2024
 * @export
 * @param {string} text
 * @param {UniApp.CanvasContext['font']} font
 * @description 当前字体样式的属性。符合 [CSS font 语法](https://developer.mozilla.org/zh-CN/docs/Web/CSS/font) 的 DOMString 字符串，至少需要提供字体大小和字体族名
 */
export function getActualWidthOfChars(text: string, font: WechatMiniprogram.CanvasContext['font'] = '14px Microsoft YaHei') {
  const canvas = wx.createOffscreenCanvas({ type: '2d' });
  const ctx = canvas.getContext('2d');
  ctx.font = font //'14px Microsoft YaHei';
  const metrics = ctx.measureText(text);
  const actual =
    Math.abs(metrics.actualBoundingBoxLeft) + Math.abs(metrics.actualBoundingBoxRight);
  return Math.max(metrics.width, actual);
}
